import { Protocol } from "../../../proto/msg";
import proto from "../../../proto/proto";
import { ClientConnection } from "../../../socket/connection/ClientConnection";
import { RoomPlayerBase } from "./RoomPlayerBase";

/**
 * 房间基类
 */
export abstract class RoomBase<T extends RoomPlayerBase> {
    /**
     * 最大玩家数量
     */
    readonly maxPlayer: number = 2;

    /**
     * 房间游戏类型
     */
    readonly kindId: number = 0;

    /**
     * 房间号
     */
    readonly roomId: number = 0;

    /**
     * 房间内玩家列表
     */
    private _players: T[] = [];
    get players() {
        return this._players;
    }

    /**
     * 房间状态
     */
    private _roomState: proto.RoomStateEnum = proto.RoomStateEnum.FREE;
    get roomState() {
        return this._roomState;
    }

    /**
     * 构造函数
     * @param kindId 房间游戏类型
     * @param roomId 房间号
     */
    constructor(kindId: number, roomId: number) {
        this.kindId = kindId;
        this.roomId = roomId;
    }

    /**
     * 是否可进入
     */
    isRoomCanEnter(): boolean {
        if (this._roomState == proto.RoomStateEnum.FREE && this._players.length < this.maxPlayer)
            return true;
        return false;
    }

    /**
     * 房间开始游戏
     */
    isRoomCanStart(): boolean {
        if (this._roomState == proto.RoomStateEnum.FREE &&
            this.players.length == this.maxPlayer &&
            this._players.every(a => a.state == proto.PlayerStateEnum.READY))
            return true;
        return false;
    }

    /**
     * 房间是否可以销毁
     */
    isRoomCanDestroy(): boolean {
        if (this._roomState == proto.RoomStateEnum.END && this._players.length == 0)
            return true;
        return false;
    }

    /**
     * 设置房间状态
     * @param state 新的房间状态
     */
    setRoomState(state: proto.RoomStateEnum) {
        this._roomState = state;
    }

    /**
     * 判断玩家是否在房间里面
     */
    hasPlayer(userId: number): boolean {
        return this._players.some(a => a.userId == userId);
    }

    /**
     * 删除玩家
     */
    removePlayer(userId: number) {
        this._players = this._players.filter(a => a.userId != userId);
    }

    /**
     * 获取玩家
     */
    getPlayer(userId: number): T | undefined {
        return this._players.find(a => a.userId == userId);
    }

    /**
     * 设置玩家状态
     */
    setPlayerState(userId: number, state: proto.PlayerStateEnum) {
        const player = this.getPlayer(userId);
        if (player) {
            player.setState(state);
        }
    }

    /**
     * 获取玩家状态
     * @param userId 
     * @returns 
     */
    getPlayerState(userId: number): proto.PlayerStateEnum {
        const player = this.getPlayer(userId);
        if (player) {
            return player.state;
        }
        return proto.PlayerStateEnum.NONE;
    }

    /**
     * 设置所有玩家状态
     */
    setAllPlayerState(state: proto.PlayerStateEnum) {
        this._players.forEach(player => {
            player.setState(state);
        });
    }

    /**
     * 设置玩家掉线状态
     */
    setOffLine(userId: number) {
        const player = this.getPlayer(userId);
        if (player) {
            player.setOffline();
        }
    }

    /**
     * 设置玩家在线
     */
    setOnline(userId: number, connection: ClientConnection) {
        const player = this.getPlayer(userId);
        if (player) {
            player.setOnline(connection);
        }
    }

    /**
     * 广播消息给房间内的所有玩家
     */
    broadcast(cmd: number, data = {}) {
        this._players.forEach(player => {
            player.connection?.pushData(cmd, data);
        });
    }
    /**
     * 广播房间状态给所有玩家
     */
    broadcastRoomState() {
        this.broadcast(Protocol.PUSH_ROOM_STATE, { state: this._roomState });
    }
    /**
     * 广播房间内玩家信息
     */
    broadcastRoomUserInfos() {
        const userInfos = this._players.map(player => {
            return {
                userId: player.userId,
                chair: player.chair,
                state: player.state,
                nickname: player.nickname,
                offline: player.offline
            }
        });
        this.broadcast(Protocol.PUSH_ROOM_USER_UPDATE, { userInfos });
    }

    /**
     * 房间初始化
     */
    abstract onInit(): void
    /**
     * 房间开始
     */
    abstract onStart(): void

    /**
     * 房间结束
     */
    abstract onDestroy(): void

    /**
     * 房间添加玩家
     */
    abstract addPlayer(userId: number): T

    /**
     * 接收客户端的消息
     */
    abstract onMsg(userId: number, cmd: number, reqWrap: proto.ReqWrap, reqData: any): void;
}